#include "sweeppolyhedra.h"

SweepPolyhedra::SweepPolyhedra(){}

SweepPolyhedra::SweepPolyhedra(BaseCurve baseCurve , Trajectory trajectory){
    //baseCurve is the beginning curve.
    calculateNormals(baseCurve , trajectory);
}

void SweepPolyhedra::calculateNormals(BaseCurve baseCurve , Trajectory trajectory){
    //Calculates the normals of all the vertices in poly and stores them in each baseCurve. baseCurve is the begginning curve.

    /*
    The present, previous, next and the next of next transformimg matrices.
    The previous, present and next transformations are used to calculate the normals of the points transformed by the present
    transformation.
    */

    double *glPresent , glPrevious[16], *glNext;

    //Booleans for the first and last instruction cases
    bool hasPreviousInstr = false , hasNextInstr = false;

    Instruction instr, instrNext;
    Trajectory localTrajectory(trajectory);

    glPushMatrix();
        while(!localTrajectory.empty()){
            instr = localTrajectory.front();
            localTrajectory.pop_front();

            hasNextInstr = true;

            glPresent = instr.transform; //The present transform matrix

            if(!localTrajectory.empty()){
                instrNext = localTrajectory.front();
                localTrajectory.pop_front();
                glNext = instrNext.transform; //The next transform matrix
                localTrajectory.push_front(instrNext);
                hasNextInstr = true;
            }
            else{
                hasNextInstr = false;
            }

            Vectors normals;

            if(!hasPreviousInstr){

                // The first instruction don't has a previous transformation
                normals = baseCurve.calculateNormals(glPresent , glNext);
                hasPreviousInstr = true;
            }
            else{
                if(hasNextInstr){
                    normals = baseCurve.calculateNormals(glPrevious , glPresent , glNext);
                }
                else{
                    normals = baseCurve.calculateNormals(glPrevious , glPresent);
                }
            }

            //Adding the curve with its normals
            Transform_3 transform(GL2CGALMatrix(glPresent));
            Points transformedPoints;
            Points::iterator it;
            for(it = baseCurve.points.begin() ; it != baseCurve.points.end() ; it++){
                transformedPoints.push_back(transform.transform(*it));
            }

            BaseCurve curve(transformedPoints , normals);
            curves.push_back(curve);

            //glPrevious = glPresent
            for(int i = 0 ; i < 16 ; i++){
                glPrevious[i] = glPresent[i];
            }
        }
    glPopMatrix();
}

void SweepPolyhedra::draw(bool showNormals){
    //Draws the entire polyhedra.

    BaseCurve begin, end;

    for(int i = 0 ; i < curves.size() - 1 ; i++){
        begin = curves.at(i);
        end = curves.at(i + 1);
        drawSection(begin , end);

        //Drawing the normals
        if(showNormals){
            glDisable(GL_LIGHTING);
                begin.drawNormals();
                end.drawNormals();
            glEnable(GL_LIGHTING);
        }
    }
}

void SweepPolyhedra::drawSection(BaseCurve begin , BaseCurve end){
    //Draws a section of the poly. Basically this operation is a extrusion of the begin to end.

    int i , j , size = begin.points.size();
    Point_3 pointBegin, pointEnd;
    Vector_3 normalBegin, normalEnd;

    glBegin(GL_QUAD_STRIP);
        for(j = 0 ; j <= size ; j++){
            i = j % size;

            pointBegin = begin.points.at(i);
            pointEnd = end.points.at(i);

            normalBegin = begin.normals.at(i);
            normalEnd = end.normals.at(i);

            glNormal3d(normalBegin.x() , normalBegin.y() , normalBegin.z());
            glVertex3d(pointBegin.x() , pointBegin.y() , pointBegin.z());

            glNormal3d(normalEnd.x() , normalEnd.y() , normalEnd.z());
            glVertex3d(pointEnd.x() , pointEnd.y() , pointEnd.z());
        }
    glEnd();
}
